package com.tf_cut.backend.request.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import com.tf_cut.backend.request.MybankApiException;
import com.tf_cut.backend.seller.enums.MybankApiExceptionEnum;
import com.tf_cut.backend.util.MybankConstants;

public class HttpsUtil {
    private volatile static HttpClient httpclient;

    private static void getHttpClient() throws MybankApiException {
        if (httpclient == null){
            synchronized (HttpsUtil.class){
                if (httpclient == null){
                    initNetwork();
                }
            }
        }
    }

    public static void close() { httpclient.getConnectionManager().shutdown(); }

    public static String httpPost(String serverUrl, List<NameValuePair> paras, String charset,
                                  String apiFunction, String apiVersion) throws MybankApiException {
        getHttpClient();

        String result = MybankConstants.NULL_STRING;
        HttpPost httppost = new HttpPost(serverUrl);
        HttpResponse response = null;
        UrlEncodedFormEntity urlEncodedFormEntity = null;
        String string = null;
        try {
            if (paras != null && paras.size() > 0) {
                urlEncodedFormEntity = new UrlEncodedFormEntity(paras);
                httppost.setEntity(urlEncodedFormEntity);
            }
            string = getEntityString(urlEncodedFormEntity);
            response = httpclient.execute(httppost);
        } catch (ClientProtocolException e) {
            MybankLogger.logCommError(e, response, serverUrl, string, apiFunction, apiVersion);
            throw new MybankApiException(MybankApiExceptionEnum.SDK_SYSTEM_EXCEPTION,e);
        } catch (IOException e) {
            MybankLogger.logCommError(e, response, serverUrl, string, apiFunction, apiVersion);
            throw new MybankApiException(MybankApiExceptionEnum.SDK_SYSTEM_EXCEPTION,e);
        }
        HttpEntity entity = null;
        if (response != null) {
            entity = response.getEntity();
        }
        if (entity != null) {
            try {
                result = EntityUtils.toString(entity, charset);
            } catch (Exception e) {
                throw new MybankApiException(MybankApiExceptionEnum.SDK_SYSTEM_EXCEPTION,e);
            }
        }
        return result;
    }

    public static String httpPost(String serverUrl, HttpEntity reqEntity, String charset,
                                  String apiFunction, String apiVersion) throws MybankApiException {
        getHttpClient();

        String result = MybankConstants.NULL_STRING;
        String string = getEntityString(reqEntity);
        HttpPost httppost = new HttpPost(serverUrl);
        HttpResponse response = null;

        try {
            httppost.setEntity(reqEntity);
            response = httpclient.execute(httppost);
        } catch (ClientProtocolException e) {
            MybankLogger.logCommError(e, response, serverUrl, string, apiFunction, apiVersion);
            throw new MybankApiException(MybankApiExceptionEnum.SDK_SYSTEM_EXCEPTION,e);
        } catch (IOException e) {
            MybankLogger.logCommError(e, response, serverUrl, string, apiFunction, apiVersion);
            throw new MybankApiException(MybankApiExceptionEnum.SDK_SYSTEM_EXCEPTION,e);
        }
        HttpEntity entity = null;
        if (response != null) {
            entity = response.getEntity();
        }
        if (entity != null) {
            try {
                result = EntityUtils.toString(entity, charset);
            } catch (Exception e) {
                throw new MybankApiException(MybankApiExceptionEnum.SDK_SYSTEM_EXCEPTION,e);
            }finally {
                try {
                    EntityUtils.consume(entity);
                } catch (IOException e) {
                    MybankLogger.logBizError(e);
                    throw new MybankApiException(MybankApiExceptionEnum.SDK_SYSTEM_EXCEPTION,e);
                }

            }
        }
        return result;
    }

    private static String getEntityString(HttpEntity reqEntity) throws MybankApiException {
        ByteArrayOutputStream out = new ByteArrayOutputStream((int) reqEntity.getContentLength());
        try {
            reqEntity.writeTo(out);
            return out.toString();
        }catch (IOException e){
            MybankLogger.logBizError(e);
            throw new MybankApiException(MybankApiExceptionEnum.SDK_SYSTEM_EXCEPTION,e);
        }finally{
            try {
                out.close();
            }catch (IOException e){
                MybankLogger.logBizError(e);
                throw new MybankApiException(MybankApiExceptionEnum.SDK_SYSTEM_EXCEPTION,e);
            }
        }
    }

    /**
     * 初始化网络模块
     */
    private static void initNetwork() throws MybankApiException {
        try {
            SSLContext ctx = SSLContext.getInstance(MybankConstants.TLS);
            X509TrustManager tm = new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType)
                        throws java.security.cert.CertificateException { }
                public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType)
                        throws java.security.cert.CertificateException { }
            };
            ctx.init(null, new TrustManager[] {tm}, null);
            SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            Scheme sch = new Scheme(MybankConstants.HTTPS, MybankConstants.HTTPS_DEFAULT_PORT, ssf);
            org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager tcm
                    = new org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager();
            tcm.setMaxTotal(10);
            tcm.getSchemeRegistry().register(sch);
            httpclient = new DefaultHttpClient(tcm);
        } catch (Exception e) {
            throw new MybankApiException(MybankApiExceptionEnum.SDK_SYSTEM_EXCEPTION,e);
        }
    }

}